平衡二叉树(AVL树)
假设一个二叉查找树中的数据都是链式的(即都集中在左子树或者右子树),那么这时候对该二叉查找树进行查找的时间复杂度就是$O(n)$,背离了二叉查找树用来优化数据查询的目的。而平衡二叉树可以使树的高度在每次插入元素后,查询操作仍然能保持$O(logn)$的时间复杂度。
对平衡二叉树的任意结点来说,要保证其左子树与右子树的高度之差绝对值不超过1,其中左子树与右子树的高度之差称为该结点的平衡因子。
// 存储结构 struct node { int data; int height; node *lchild; node *rchild; }; // 新建结点 node *newNode(int n) { node *Node = new node; Node->data = n; Node->height = 1; Node->lchild = Node->rchild = NULL; return Node; } // 获得结点所在子树高度 int getHeight(node *root) { if(root == NULL) return 0; return root->height; } // 计算平衡因子 int getBalanceFactor(node *root) { return getHeight(root->lchild) - getHeight(root->rchild); } void updateHeight(node *root) { root->height = max(getHeight(root->lchild),getHeight(root->rchild))+1; } // 查找操作与二叉查找树一样,不过因为AVL树高度为O(logn) 所以时间复杂度也为O(logn) // 左旋 Left Rotation void L(node *&root) { node *temp = root->rchild; root->rchild = temp->lchild; temp->lchild = root; updateHeight(root); updateHeight(temp); root = temp; } // 右旋 (Right Rotation) void R(node *&root) { node *temp = root->lchild; root->lchild = temp->rchild; temp->rchild = root; updateHeight(root); updateHeight(temp); root = temp; }
在往已有的AVL树中插入一个结点,一定会有结点的平衡因子发生变化,此时可能会有结点的平衡因子绝对值大于1(大于1的可能只有2或者-2)。显然只有在从根结点到该插入结点的路径上的结点才可能发生平衡因子变化,因此可以证明,只要把最靠近插入结点的失衡结点调整正常,路径上所有结点就会回复平衡。
假设结点A、B、C的权值满足A>B>C
此时A平衡因子为2,当A的左孩子平衡因子为1时为LL型,A的左孩子平衡因子为-1时为LR型。
LL型:把C为根结点的子树看作整体,以结点A为root进行右旋
LR型:以结点C为root进行左旋,转化为LL型,再按LL型处理
此时A平衡因子为-2,当A的右孩子平衡因子为-1时为RR型,A的右孩子平衡因子为1时为RL型。
RR型:把C为根结点的子树看作整体,以结点A为root进行左旋
RL型:以结点C为root进行右旋,转化为RR型,再按RR型处理
// 往AVL中插入结点 void insert(node *&root,int v) { if(root==NULL) { root = newNode(v); return; } if(v <= root->data) { insert(root->lchild,v); updataHeight(root); // 更新树高 if(getBalanceFactor(root) == 2) { if(getBalanceFactor(root->lchild)==1) // LL型 { R(root); } else if(getBalanceFactor(root->lchild)==-1) // LR型 { L(root->lchild); R(root); } } } else if(v > root->data) { insert(root->rchild,v); updateHeight(root); if(getBalanceFactor(root) == -2) { if(getBalanceFactor(root->rchild) == 1) // RR型 { L(root); } else if(getBalanceFactor(root->rchild) == -1) // RL型 { R(root->rchild); L(root); } } } } // 建立AVL树 node *create(int data[],int n) { node *root = new node; for(int i=0;i<n;++i) insert(root,data[i]); return root; }